home *** CD-ROM | disk | FTP | other *** search
/ MIDICraft's MIDINET CD-ROM / MIDICraft's MIDINET CD-ROM.iso / DOSUTILS / MAPNOTES.ZIP / MAPNOTES.CPP < prev    next >
C/C++ Source or Header  |  1997-03-11  |  8KB  |  368 lines

  1. // mapnotes v1.0 written by Günter Nagler 1996 (gnagler@ihm.tu-graz.ac.at)
  2. #include "midiio.hpp"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6.  
  7. #ifdef __MSDOS__
  8. #define WRITE_BINARY  "wb"
  9. #define READ_BINARY   "rb"
  10. #else
  11. #define WRITE_BINARY  "w"
  12. #define READ_BINARY   "r"
  13. #endif
  14.  
  15. char* input = 0;
  16. char* output = 0;
  17. char* changename = "mapnotes.chg";
  18.  
  19. int quiet = 0;
  20. int changechannel[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  21.  
  22. int changenote[128];
  23.  
  24. class MidiChangeNotes : public MidiCopy
  25. {
  26. public:
  27.   MidiChangeNotes(char* name);
  28.  
  29.   virtual void noteon(int channel, int note, int vel);
  30.   virtual void noteoff(int channel, int note, int vel);
  31.   virtual void error(const char* msg);
  32.  
  33.   virtual void percent(int perc);
  34. };
  35.  
  36. MidiChangeNotes::MidiChangeNotes(char* name) : MidiCopy(name)
  37. {
  38.   options_ = OPTION_NOSYSEVENTS | OPTION_NOMETAEVENTS | OPTION_NOCONTROLS;
  39. }
  40.  
  41. void MidiChangeNotes::noteon(int channel, int note, int vel)
  42. {
  43.   if (changechannel[channel])
  44.   {
  45.     note = changenote[note];
  46.   }
  47.   MidiCopy::noteon(channel, note, vel);
  48. }
  49.  
  50. void MidiChangeNotes::noteoff(int channel, int note, int vel)
  51. {
  52.   if (changechannel[channel])
  53.   {
  54.     note = changenote[note];
  55.   }
  56.   MidiCopy::noteoff(channel, note, vel);
  57. }
  58.  
  59. void MidiChangeNotes::percent(int perc)
  60. {
  61.   if (!quiet)
  62.     fprintf(stderr, "%-3d%%\r", perc);
  63. }
  64.  
  65. void MidiChangeNotes::error(const char* msg)
  66. {
  67.   printf("// error: %s\n", msg);
  68. }
  69.  
  70. void usage()
  71. {
  72.   fprintf(stderr, "mapnotes changes notes in midi files\n");
  73.   fprintf(stderr, "usage: mapnotes [-chg file.chg] [-c #[-#]] [-quiet] file.mid changed.mid\n");
  74.   fprintf(stderr, "-chg file.chg\tload note changes from file.chg (default is mapnotes.chg)\n");
  75.   fprintf(stderr, "-c #\t\tmodify programs on channel (1-16, default: all channels except GM drum channel 10)\n");
  76.   fprintf(stderr, "-quiet\t\tbe quiet! does not write percentage info\n");
  77.   exit(1);
  78. }
  79.  
  80. char* loadline(FILE* f, char* s)
  81. {
  82. int c;
  83. char* t = s;
  84.  
  85.   while ((c = fgetc(f)) != EOF && c != '\n')
  86.   {
  87.     if (c == '\r')
  88.       continue;
  89.     *t++ = c;
  90.   }
  91.   *t = 0;
  92.   if (c == EOF && s == t)
  93.     return 0;
  94.   return s;
  95. }
  96.  
  97. char* skipws(char* &s)
  98. {
  99.   while (*s != 0 && isspace(*s))
  100.       s++;
  101.   return s;
  102. }
  103.  
  104. char* getword(char* &s)
  105. {
  106. static char word[256];
  107. char* w = word;
  108.  
  109.   skipws(s);
  110.   w = word;
  111.   while (*s != 0 && !isspace(*s))
  112.     *w++ = *s++;
  113.   *w = '\0';
  114.   return word;
  115. }
  116.  
  117. static char* GMNote[128] =
  118. {
  119.   "C0","C#0","D0","D#0","E0","F0","F#0","G0","G#0","A0","A#0","B0",
  120.   "C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1","A1","A#1","B1",
  121.   "C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2",
  122.   "C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3",
  123.   "C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4",
  124.   "C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5","A5","A#5","B5",
  125.   "C6","C#6","D6","D#6","E6","F6","F#6","G6","G#6","A6","A#6","B6",
  126.   "C7","C#7","D7","D#7","E7","F7","F#7","G7","G#7","A7","A#7","B7",
  127.   "C8","C#8","D8","D#8","E8","F8","F#8","G8","G#8","A8","A#8","B8",
  128.   "C9","C#9","D9","D#9","E9","F9","F#9","G9","G#9","A9","A#9","B9",
  129.   "C10","C#10","D10","D#10","E10","F10","F#10","G10"
  130. };
  131.  
  132. int equali(char* s1, char* s2)
  133. {
  134.   if (!s1 || !s2)
  135.     return 0;
  136.   while (*s1 != 0 && *s2 != 0)
  137.     if (toupper(*s1++) != toupper(*s2++))
  138.       return 0;
  139.   if (*s1 != *s2)
  140.     return 0;
  141.   return 1;
  142. }
  143.  
  144. int getnumber(char* word)
  145. {
  146. char* s = word;
  147. int v = 0;
  148.  
  149.   if (*s == '-')
  150.     return -1;
  151.   if (isdigit(*s))
  152.   {
  153.     while (*s && isdigit(*s))
  154.       v = v * 10 + (*s++ - '0');
  155.   }
  156.   else if (*s == '$' || strncmp(s, "0x",2) == 0 ||strncmp(s, "0X", 2) == 0)
  157.   {
  158.     if (*s == '$')
  159.       s++;
  160.     else
  161.       s+=2;
  162.     while (*s && isxdigit(*s))
  163.     {
  164.       if (isdigit(*s))
  165.     v = (v << 4) + (*s - '0');
  166.       else
  167.     v = (v << 4) + (toupper(*s) - 'A' + 10);
  168.       s++;
  169.     }
  170.   }
  171.   else
  172.   {
  173.     fprintf(stderr, "Number expected instead of %s\n", word);
  174.     return -1;
  175.   }
  176.   if (*s != '\0')
  177.     fprintf(stderr, "Invalid characters in number %s\n", word);
  178.   return v;
  179. }
  180.  
  181. int getnote(char* s)
  182. {
  183.   if (strcmp(s, "-") == 0)
  184.     return -1;
  185.   for (int i = 0; i < 128; i++)
  186.     if (equali(s, GMNote[i]))
  187.        return i;
  188.  
  189.   return getnumber(s);
  190. }
  191.  
  192. int loadchangetable(char* filename)
  193. {
  194. FILE* f = fopen(filename, READ_BINARY);
  195. static char line[256];
  196. char *lp;
  197. int oldnote, newnote;
  198.  
  199.   for (int i = 0; i < 128;i++)
  200.     changenote[i] = i;
  201.  
  202.   if (!f)
  203.   {
  204.     perror(filename);
  205.     return 0;
  206.   }
  207.  
  208.   while (loadline(f, line))
  209.   {
  210.   char* word;
  211.  
  212.     lp = line;
  213.  
  214.     word = strchr(lp, ';');  // remove comment!
  215.     if (word)
  216.       *word = '\0';
  217.  
  218.     // get note name
  219.     word = getword(lp);
  220.     if (*word == 0)     // empty line!
  221.       continue;
  222.  
  223.     oldnote = getnote(word);
  224.  
  225.     if (oldnote < 0)
  226.       continue;
  227.  
  228.     skipws(lp);
  229.     if (strncmp(lp, "=>", 2) == 0)
  230.       lp += 2;
  231.  
  232.     word = getword(lp);
  233.     // get note value (can be empty (-))
  234.     if (!*word)
  235.     {
  236.       fprintf(stderr, "invalid line format: %s\n", line);
  237.       continue;
  238.     }
  239.     newnote = getnote(word);
  240.  
  241.     changenote[oldnote] = newnote;
  242.   }
  243.   fclose(f);
  244.   return 1;
  245. }
  246.  
  247. int main(int argc, char**argv)
  248. {
  249.   argc--; argv++;
  250.   while (argc > 0 && **argv == '-')
  251.   {
  252.     if (strncmp(*argv, "-chg", 3) == 0)
  253.     {
  254.       argc--; argv++;
  255.       if (argc == 0)
  256.       {
  257.     fprintf(stderr, "option -chg needs filename parameter\n");
  258.     continue;
  259.       }
  260.       changename = *argv++; argc--;
  261.       continue;
  262.     }
  263.     if (strncmp(*argv, "-c", 2) == 0)
  264.     {
  265.     int firstchannel, secondchannel;
  266.  
  267.       argc--; argv++;
  268.       if (argc > 0 && sscanf(*argv, "%u-%u", &firstchannel, &secondchannel) == 2)
  269.       {
  270.     if (firstchannel <= 0 || secondchannel > 16)
  271.     {
  272.       fprintf(stderr, "channel number %s out of range 1-16\n", *argv);
  273.       firstchannel = secondchannel = -1;
  274.     }
  275.     else if (firstchannel > secondchannel)
  276.     {
  277.       fprintf(stderr, "%s: first channel number must be less than second one\n", *argv);
  278.       firstchannel = secondchannel = -1;
  279.     }
  280.     argc--; argv++;
  281.       }
  282.       else if (argc > 0 && isdigit(**argv))
  283.       {
  284.     firstchannel = atoi(*argv);
  285.     if (firstchannel <= 0 || firstchannel > 16)
  286.     {
  287.       fprintf(stderr, "channel number %s out of range 1-16\n", *argv);
  288.       firstchannel = -1;
  289.     }
  290.     secondchannel = firstchannel;
  291.     argc--; argv++;
  292.       }
  293.       else
  294.       {
  295.     fprintf(stderr, "option -mapchannel expects two channel numbers 1-16\n");
  296.     usage();
  297.     break;
  298.       }
  299.       for (int i = firstchannel; i <= secondchannel; i++)
  300.        changechannel[i] = 1;
  301.       continue;
  302.     }
  303.     if (strncmp(*argv, "-quiet", 2) == 0)
  304.     {
  305.       quiet = 1;
  306.       argc--; argv++; continue;
  307.     }
  308.     fprintf(stderr, "invalid option %s\n", *argv);
  309.     argc--; argv++;
  310.     usage();
  311.   }
  312.   for (int i = 0; i < 16; i++)
  313.   if (changechannel[i])
  314.     break;
  315.   if (i >= 16) // no channel set => modify all channels
  316.   {
  317.     for (i = 0; i < 16; i++)
  318.       changechannel[i] = 1;
  319.     changechannel[9] = 0; // gm drum
  320.   }
  321.  
  322.   if (!loadchangetable(changename))
  323.     return 0;
  324.  
  325.   if (argc < 2)
  326.     usage();
  327.  
  328.   input = argv[0];
  329.   output = argv[1];
  330.   if (strcmp(input, output) == 0)
  331.   {
  332.     fprintf(stderr, "cannot convert midi to same file\n");
  333.     return 1;
  334.   }
  335.  
  336.   MidiChangeNotes midi(input);
  337.   if (!midi.getf())
  338.   {
  339.     perror(input);
  340.     return 1;
  341.   }
  342.   MidiWrite* write = new MidiWrite(output);
  343.   if (!write)
  344.   {
  345.     fprintf(stderr, "out of memory\n");
  346.     return 1;
  347.   }
  348.   if (!write->getf())
  349.   {
  350.     perror(output);
  351.     return 1;
  352.   }
  353.  
  354.   midi.setoutput(write);
  355.  
  356.   midi.options_ = OPTION_NOSYSEVENTS;
  357.  
  358.   argc--; argv++;
  359.   if (!midi.run())
  360.     fprintf(stderr, "%s: midi read error at %04lX\n", input, midi.getpos());
  361.  
  362.   delete write;
  363.  
  364.   return 0;
  365. }
  366.  
  367.  
  368.